/*
 * Copyright (c) 2006-2018, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2019-04-10     ZYH          first version
 */

#include <rtthread.h>

#ifdef BSP_USING_USBD_FS
#include <rtdevice.h>
#include "board.h"
#include <string.h>
#include <drv_config.h>
#include "hw_config.h"
#include "usbfsd_lib.h"
#include "usbfsd_pwr.h"
#include "usbfsd_istr.h"
#include "n32h47x_48x_exti.h"

static struct rt_device USB_VrCom;

/**
*\*\name    USB_FS_WKUP_IRQHandler.
*\*\fun     This function handles USB WakeUp interrupt request.
*\*\param   none
*\*\return  none 
**/
void USB_FS_WKUP_IRQHandler(void)
{
    rt_interrupt_enter();
    EXTI_ClrITPendBit(EXTI_LINE18);
    /* leave interrupt */
    rt_interrupt_leave();
}

void USB_FS_LP_IRQHandler(void)
{
    rt_interrupt_enter();
    USB_Istr();
    /* leave interrupt */
    rt_interrupt_leave();
}

rt_err_t  _init  (rt_device_t dev)
{
    rt_err_t result = RT_EOK;
    USBFS_IO_Configure();
    USB_Interrupts_Config();
    if (USB_Config(SYSCLK_VALUE_240MHz) != SUCCESS) {
        result = RT_ERROR;
    }
    USB_Init();
    return result;
}

rt_err_t  _open   (rt_device_t dev, rt_uint16_t oflag)
{
    // PowerOn();
    // _EnPortPullup();
    // LOG_D("USB OPEN");

    return RT_EOK;
}

rt_err_t  _close  (rt_device_t dev)
{
    // PowerOff();
    // _DisPortPullup();
    // LOG_D("USB CLOSE");

    return RT_EOK;
}

rt_size_t _read   (rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
{
    if (bDeviceState != CONFIGURED) return 0;
    if (size == 0) return 0;
    uint16_t rxLen = size;
    USB_ReceiveData(buffer, &rxLen);

    return rxLen;
}


rt_size_t _write  (rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
{
    if (bDeviceState != CONFIGURED){
        return 0;
    }
    uint16_t txLen = size;

    if (dev->open_flag & RT_DEVICE_FLAG_STREAM) {
        uint8_t *ptr = (uint8_t *)buffer;
        while (size--)        {
            if (*ptr == '\n') {
                USB_BufferByte('\r');
            }
            USB_BufferByte(*ptr);
            ptr++;
        }
        USB_SenData((uint8_t *)buffer, NULL);   // judge the txFlag
    } else {
        txLen = USB_SenData((uint8_t *)buffer, size);
    }
    return txLen;
}

/*Get the device config state*/
rt_err_t  _control(rt_device_t dev, int cmd, void *args)
{
    rt_err_t result = RT_EOK;

    if (bDeviceState != CONFIGURED) {
        result = RT_ERROR;
    }
    return result;
}

void usbd_RxIndCallBack(uint16_t rxLen)
{
    if (USB_VrCom.rx_indicate != RT_NULL) {
        USB_VrCom.rx_indicate(&USB_VrCom, rxLen);
    }
}

int usbd_register(void)
{
    rt_memset((void *)&USB_VrCom, 0, sizeof(struct rt_device));
    USB_VrCom.type        = RT_Device_Class_USBDevice;
    USB_VrCom.rx_indicate = RT_NULL;
    USB_VrCom.tx_complete = RT_NULL;

    USB_VrCom.init    = _init;
    USB_VrCom.close   = _close;
    USB_VrCom.open    = _open;
    USB_VrCom.write   = _write;
    USB_VrCom.read    = _read;
    USB_VrCom.control = _control;
    USB_VrCom.user_data = RT_NULL;
    

    rt_device_register(&USB_VrCom, "usbd", 0);
    return RT_EOK;
}
#endif
